home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 4
/
Apprentice-Release4.iso
/
Source Code
/
C
/
Games
/
Mine Sweeper 1.1
/
Source
/
mine.c
< prev
next >
Wrap
Text File
|
1994-04-26
|
13KB
|
470 lines
/* mine.c
*
* How to handle the window for mining
*/
#include <stdlib.h>
#include "event.h"
#include "mines.h"
#define HEIGHT 20 /* Border height */
/****************************************************************/
/* */
/* Support Routines */
/* */
/****************************************************************/
/* DrawSICN
*
* Draw this small icon
*/
static void DrawSICN(Rect rr, short i)
{
BitMap bmap;
Handle h;
GrafPtr foo;
Rect s;
h = GetResource('SICN',128);
if (h == NULL) return;
HLock(h);
bmap.baseAddr = *h;
s.left = 0;
s.right = 16;
s.top = i * 16;
s.bottom = s.top + 16;
bmap.bounds = s;
bmap.bounds.top = 0;
bmap.rowBytes = 2;
GetPort(&foo);
CopyBits(&bmap,&(foo->portBits),&s,&rr,0,NULL);
HUnlock(h);
}
/* GenBombs
*
* This generates the bomb locations
*/
void GenBombs(void)
{
short i,x,y;
short a,b;
for (x = 0; x < 40; x++) for (y = 0; y < 40; y++) {
BPosition[x][y] = 0;
BStatus[x][y] = 0;
}
for (i = 0; i < Bombs; i++) {
do {
x = Random() % SizeX; if (x < 0) x += SizeX;
y = Random() % SizeY; if (y < 0) y += SizeY;
} while (BPosition[x][y]);
BPosition[x][y] = -1;
}
for (x = 0; x < 40; x++) for (y = 0; y < 40; y++) {
if (BPosition[x][y] == -1) continue;
i = 0;
for (a = -1; a <= 1; a++) {
if (a + x < 0) continue;
if (a + x >= SizeX) continue;
for (b = -1; b <= 1; b++) {
if (b + y < 0) continue;
if (b + y >= SizeY) continue;
if (BPosition[a+x][b+y] == -1) i++;
}
}
BPosition[x][y] = i;
}
}
/* FindLocation
*
* This computes the location
*/
Rect FindLocation(short x, short y)
{
Rect r;
r.left = x * 16 - 1;
r.top = y * 16 + HEIGHT;
r.right = r.left + 16;
r.bottom = r.top + 16;
return r;
}
/* FillFailure
*
* This fills in the failure states when this click fails
*/
static void FillFailure(void)
{
short a,b;
for (a = 0; a < SizeX; a++) for (b = 0; b < SizeY; b++) {
if (BPosition[a][b] != -1) {
if (BStatus[a][b] == 1) BStatus[a][b] = 4;
} else {
if (BStatus[a][b] == 0) BStatus[a][b] = 1;
else if (BStatus[a][b] == 2) BStatus[a][b] = 1;
}
DrawSICN(FindLocation(a,b),BStatus[a][b]);
}
}
/* ClearPoint
*
* Given a point, this attempts to handle the click in this point
*/
static void ClearPoint(short i,short j, short flag)
{
if (i < 0) return;
if (j < 0) return;
if (i >= SizeX) return;
if (j >= SizeY) return;
if (BState) return; /* Ack! Don't do anything */
if (BStatus[i][j] == 0) { /* Status is cleared */
if (BPosition[i][j] == -1) { /* Position has bomb; die */
BState = 1;
BStatus[i][j] = 5;
DrawSICN(FindLocation(i,j),BStatus[i][j]);
FillFailure();
} else if (BPosition[i][j] > 0) { /* Position is not friendly */
BStatus[i][j] = BPosition[i][j] + 5;
DrawSICN(FindLocation(i,j),BStatus[i][j]);
if (Cruse) {
short a,b; /* See if total marked are okay */
short count;
short n;
/*
* Cruse control: if I'm clicking on this cell, and the
* number of marked items match, then continue.
*/
count = 0;
for (a = -1; a <= 1; a++) for (b = -1; b <= 1; b++) {
if (a + i < 0) continue;
if (b + j < 0) continue;
if (a + i >= SizeX) continue;
if (b + j >= SizeY) continue;
n = BStatus[a+i][b+j];
if (n == 1) count++;
}
if (count == BPosition[i][j]) { /* Count match */
for (a = -1; a <= 1; a++) for (b = -1; b <= 1; b++) {
if (a + i < 0) continue;
if (b + j < 0) continue;
if (a + i >= SizeX) continue;
if (b + j >= SizeY) continue;
if (BStatus[a+i][b+j] == 1) continue;
ClearPoint(a+i,b+j,flag+1);
}
}
}
} else { /* Position is friendly. */
short a,b;
BStatus[i][j] = 3;
DrawSICN(FindLocation(i,j),BStatus[i][j]);
for (a = -1; a <= 1; a++) for (b = -1; b <= 1; b++) {
ClearPoint(i+a,b+j,flag+1);
}
}
} else if ((BStatus[i][j] >= 6) && (!flag)) { /* Status has value */
short num = 0;
short a,b;
short count = 0;
for (a = -1; a <= 1; a++) for (b = -1; b <= 1; b++) {
if ((a+i<0) || (b+j<0)) continue;
if ((a+i>=SizeX) || (b+j>=SizeY)) continue;
if (BStatus[a+i][b+j] == 1) num++, count++;
if (BStatus[a+i][b+j] == 2) count++;
if (BStatus[a+i][b+j] == 0) count++;
}
if (num < BPosition[i][j]) {
/*
* Cruse Control #2: If I click on a cell which has a match between
* the number of unclicked objects and the number in the cell, then
* this marks those objects
*/
if (Cruse && (count == BPosition[i][j])) {
for (a = -1; a <= 1; a++) for (b = -1; b <= 1; b++) {
if ((a+i<0) || (b+j<0)) continue;
if ((a+i>=SizeX) || (b+j>=SizeY)) continue;
if ((BStatus[a+i][b+j] == 2) || (BStatus[a+i][b+j] == 0)) {
BStatus[a+i][b+j] = 1;
DrawSICN(FindLocation(a+i,b+j),BStatus[a+i][b+j]);
}
}
}
} else {
for (a = -1; a <= 1; a++) for (b = -1; b <= 1; b++) {
ClearPoint(a+i,b+j,flag+1);
}
}
}
}
/* ScanUniverse
*
* This scans through my entire universe, calling ClearPoint over and over again
* if any entry point with a count has the same number of uncovered or marked points
* as the point provided.
*/
static void ScanUniverse(void)
{
short a,b;
short i,j;
short n,count;
short cover;
short nbomb;
if (!Cruse) return; /* Cruse control is not on */
if (BState) return; /* The state routine fails */
for (a = 0; a < SizeX; a++) for (b = 0; b < SizeY; b++) {
if (BStatus[a][b] < 6) continue;
count = 0;
cover = 0;
nbomb = 0;
for (i = -1; i <= 1; i++) for (j = -1; j <= 1; j++) {
if (a + i < 0) continue;
if (b + j < 0) continue;
if (a + i >= SizeX) continue;
if (b + j >= SizeY) continue;
n = BStatus[a+i][b+j];
if ((n == 0) || (n == 1) || (n == 2)) count++;
if (n == 0) cover++;
if (n == 1) nbomb++;
}
if ((BPosition[a][b] == count) && (cover > 0)) { /* Click if bomb is here */
ClearPoint(a,b,0);
a = 0;
b = -1; /* Force restart */
}
if ((BPosition[a][b] == nbomb) && (cover > 0)) { /* Click if nbombs same */
ClearPoint(a,b,0);
a = 0;
b = -1; /* Force restart */
}
}
}
/* TestWin
*
* Scan to see if I won
*/
void TestWin()
{
short a,b;
short i1;
Handle i2;
Rect i3;
for (a = 0; a < SizeX; a++) for (b = 0; b < SizeY; b++) {
if (BStatus[a][b] == 0) return;
if (BStatus[a][b] == 2) return; /* Fail */
if (BStatus[a][b] == 1) {
if (BPosition[a][b] == -1) continue;
return;
}
if (BStatus[a][b] == 3) continue;
if (BStatus[a][b] == 4) return;
if (BStatus[a][b] == 5) return;
}
/*
* If I made it here, there are no clears, no questions, and every
* mark is correct, then I won
*/
SysBeep(5);
BState = 1;
BCount = 0;
if ((SizeFlag != 2) || (BombFlag != 1)) return;
for (a = 0; a < 4; a++) {
if (CurTime < Scores[a].time) break;
}
if (a == 4) return;
for (b = 3; b > a; b--) {
Scores[b] = Scores[b-1];
}
Scores[a].time = CurTime;
GetUserName(Scores[a].name);
}
/****************************************************************************/
/* */
/* Window management routines */
/* */
/****************************************************************************/
/* NewMines
*
* This opens the mines window (if state is cleared)
*/
void NewMines(void)
{
Rect r;
short x = XLoc, y = YLoc;
if (MineWindow != NULL) {
x = MineWindow->portRect.left - MineWindow->portBits.bounds.left;
y = MineWindow->portRect.top - MineWindow->portBits.bounds.top;
}
r.left = x;
r.right = r.left - 1 + 16 * SizeX;
r.top = y;
r.bottom = r.top + HEIGHT + 16 * SizeY;
if (MineWindow == NULL) {
MineWindow = NewWindow(NULL,&r,"\pMines",1,4,(WindowPtr)-1L,1,0L);
SetPort(MineWindow);
} else {
SetPort(MineWindow);
EraseRect(&(MineWindow->portRect));
SizeWindow(MineWindow,r.right-r.left,r.bottom-r.top,0);
InvalRect(&(MineWindow->portRect));
}
((WindowPeek)MineWindow)->windowKind = WK_GAME;
Bombs = (SizeX * SizeY) / BRatio; /* Bomb count ratio */
BState = 0; /* Start game over again */
BFirst = 1;
GenBombs(); /* And generate some bombs */
LogTime = TickCount(); /* Store current time */
CurTime = -1;
}
/* DrawInteger
*
* This draws the integer provided on the display at the location specified
*/
void DrawInteger(short val, short px, short py)
{
Rect r;
short x;
short y;
char buffer[32];
char *a;
ForeColor(redColor);
r.top = py; r.bottom = r.top + 16;
r.left = px + 32; r.right = r.left + 16;
NumToString(val,(unsigned char *)buffer);
y = buffer[0];
if (y <= 3) {
for (x = 0; x < y; x++) buffer[x] = buffer[x+1];
buffer[x] = '\0';
} else {
buffer[0] = '-';
buffer[1] = '-';
buffer[2] = '-';
buffer[3] = '\0';
}
for (a = buffer; *a != '\0'; a++);
y = 3;
while (--a >= buffer) {
if (*a == '-') DrawSICN(r,16);
else DrawSICN(r,17+(*a-'0'));
OffsetRect(&r,-16,0);
}
while (y >= 0) {
EraseRect(&r);
OffsetRect(&r,-16,0);
y--;
}
ForeColor(blackColor);
}
/* DoPeriodic
*
* This handle periodic events. The only thing that happens periodically
* is the timer
*/
void DoPeriodic(void)
{
long time;
if (BState) return;
time = (TickCount() - LogTime)/60;
if (time == CurTime) return;
SetPort(MineWindow);
DrawInteger((short)(CurTime = time),(MineWindow->portRect.right)-50,2);
}
/* CountUpdate
*
* Draw the score
*/
void CountUpdate(void)
{
short i,j;
if (!BState) {
BCount = 0;
for (i = 0; i < SizeX; i++) for (j = 0; j < SizeY; j++) {
if (BPosition[i][j] == -1) BCount++;
}
for (i = 0; i < SizeX; i++) for (j = 0; j < SizeY; j++) {
if (BStatus[i][j] == 1) BCount--;
}
}
DrawInteger((long)BCount,2,2);
DrawInteger((short)CurTime,(MineWindow->portRect.right)-50,2);
}
/* UpdateMines
*
* This updates the mines display
*/
void UpdateMines(WindowPtr w)
{
short i,j;
short minx,maxx,miny,maxy;
Rect r;
CountUpdate();
/*
* Draw the contents display
*/
r = (**(w->visRgn)).rgnBBox;
r.left = (r.left+1)/16;
r.right = (r.right/16)+1;
r.top = (r.top-HEIGHT+1)/16;
r.bottom = (r.bottom-HEIGHT+2